package cc.wanforme.st.server.authen.anno;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.function.BiFunction;
import java.util.function.Supplier;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

/**
 * 通用权限认证注解拦截器。<br>
 * 便于理解，参考简化版: {@link cc.wanforme.st.server.authen.anno.HasPermissionAuthorizationManager}
 * 
 * @param <A>
 */
public class GenericAuthorizationManager<A extends Annotation> 
		implements AuthorizationManager<MethodInvocation> {

	private Class<A> annotationType;
	// 用于检查是否权限 GrantedAuthority 与 注解 A 
	private BiFunction<GrantedAuthority, A, Boolean> predicate ;
	
	/**
	 * @param annotationType 注解类型
	 * @param predicate GrantedAuthority 与 注解 A，返回值 Boolean 为true则认证通过。
	 */
	public GenericAuthorizationManager(Class<A> annotationType,
			BiFunction<GrantedAuthority, A, Boolean> predicate) {
		this.annotationType = annotationType;
	}
	
	@Override
	public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
		Authentication auth = authentication.get();
		Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
		
		// 寻找注解
		A anno = AnnotationUtils.findAnnotation(mi.getMethod(), annotationType);
		if(anno == null) { // 不存在此情况
			return new AuthorizationDecision(false);
		}
		
		// 筛选权限
		boolean match = authorities.stream()
			.anyMatch(e -> predicate.apply(e, anno));

		return new AuthorizationDecision(match);
	}

}
